<?php

// @formatter:off
/**
 * @file WCParserBehaviorIF.php
 * @author Alejandro Dario Simi
 * @date $Date: 2014-05-04 01:33:52 +0000 (Sun, 04 May 2014) $
 *
 * $Id: WCParserBehaviorIF.php 111 2014-05-04 01:33:52Z daemonraco@gmail.com $
 * $URL: http://wcomix.googlecode.com/svn/trunk/includes/parser/WCParserBehaviorIF.php $
 */
// @formatter:on

/**
 * @class WCParserBehaviorIF This is a specific behavior that emulates an IF
 * evaluation. When it's used it looks like:
 * @code
 * <:IF:!:var=name:value=3:/>content<::/>
 * @endcode
 */
class WCParserBehaviorIF extends WCParserBehavior {
	/**
	 * @var string This is the type of warnings used when a IF condition is
	 * created but there's no variable to evaluate.
	 */
	const WarningNONAME = "IF_NONAME";
	/**
	 * @var string This is the type of warnings used when a variable has to be
	 * an array and it's not.
	 */
	const WarningNOTARRAY = "IF_NOTARRAY";
	/**
	 * This method perform a check of the object, sets the current status
	 * (variable $this->_ok) and return it.
	 *
	 * @return boolean Returns the current status after a check.
	 */
	public function check() {
		//
		// An IF behavior must belong to a parser node.
		if($this->_node) {
			//
			// An IF behavior requires one parameter at least
			if(count($this->_node->params()) < 1) {
				//
				// Behavior has no parameters. Error message is
				// set and the internal status becomes false.
				$this->_errorMsg = "IF without parameters";
				$this->_ok = false;
			} else {
				//
				// At this point, everything checks out.
				$this->_ok = true;
				$this->_errorMsg = "Ok";
			}
		} else {
			//
			// Behavior's node is not present. Error message is set
			// and the internal status becomes false.
			$this->_errorMsg = "IF node is not set";
			$this->_ok = false;
		}
		//
		// Returning current object status.
		return $this->isOk();
	}
	/**
	 * This method actually performs the IF based on its node's data.
	 *
	 * @return string If the evaluated IF condition is true, it returns the
	 * nodes contents, and an empty string when false. Otherwise, returns
	 * false.
	 */
	public function get() {
		//
		// Setting the default value to be returned.
		$out = false;
		//
		// IF condition will only be evaluated when this behavior has no
		// issues.
		if($this->isOk()) {
			//
			// Setting the default value of the evaluation.
			$isTrue = false;
			//
			// Loading parameters from the behavior's node.
			$params = $this->_node->params();
			//
			// Getting the name of the variable to be analyzed.
			$varname = isset($params["var"]) ? $params["var"] : false;
			//
			// Checking that there is a variable to evaluate.
			if(!$varname) {
				//
				// There's no variable name set, therefore, a
				// warning message is added.
				$this->_parser->setWarning(WCParserBehaviorIF::WarningNONAME, "No variable set", false, false, __CLASS__);
			} else {
				//
				// Checking that there is variable assigned in the
				// parser for the name given in the parameters.
				if(!$this->_parser->has($varname)) {
					//
					// The variable name belongs to not yet
					// set variable, therefore, a warning
					// message is added.
					$this->_parser->setWarning(WCParser::WarningUNSET_VARIABLE, "Variable '{$varname}' is not set", false, false, __CLASS__);
				} else {
					//
					// Analyzing the condition to be checked.
					if(isset($params["value"])) {
						//
						// When a parameter 'value' is
						// set, the variable must match
						// the value.
						$isTrue = ($this->_parser->$varname == $params["value"]);
					} elseif(isset($params["to"])) {
						//
						// When a parameter 'to' is set,
						// the variable must match the
						// value of another variable with
						// the name given by the parameter
						// 'to'.
						$subvarname = $params["to"];
						if(!$this->_parser->has($subvarname)) {
							//
							// At this point, the second variable is not yet set, therefore, a warning message
							// is added.
							$this->_parser->setWarning(WCParser::WarningUNSET_VARIABLE, "Variable '{$subvarname}' is not set", false, false, __CLASS__);
						} else {
							$isTrue = ($this->_parser->$varname == $this->_parser->$subvarname);
						}
					} elseif(isset($params["in"])) {
						//
						// When a parameter 'in' is set,
						// the variable must be an element
						// of an array which name is given
						// by the parameter 'in'.
						$subvarname = $params["in"];
						if(!$this->_parser->has($subvarname)) {
							//
							// At this point, the second variable is not yet set, therefore, a warning message
							// is added.
							$this->_parser->setWarning(WCParser::WarningUNSET_VARIABLE, "Variable '{$subvarname}' is not set", false, false, __CLASS__);
						} elseif(!is_array($this->_parser->$subvarname)) {
							//
							// At this point, the second variable is set, but it's not an array. therefore, a
							// warning message is added.
							$this->_parser->setWarning(WCParserBehaviorIF::WarningNOTARRAY, "Variable '{$subvarname}' is not an array", false, false, __CLASS__);
						} else {
							$isTrue = in_array($this->_parser->$varname, $this->_parser->$subvarname);
						}
					} elseif(isset($params["count"])) {
						//
						// When a parameter 'count' is set
						// the variable must be an array
						// and it must have as many
						// element as the number given by
						// the parameter 'count'.
						if(!is_array($this->_parser->$varname)) {
							//
							// At this point, the variable is not an array. therefore, a warning message is
							// added.
							$this->_parser->setWarning(WCParserBehaviorIF::WarningNOTARRAY, "Variable '{$varname}' is not an array", false, false, __CLASS__);
						} else {
							$isTrue = (is_array($this->_parser->$varname) && count($this->_parser->$varname) == $params["count"]);
						}
					} else {
						//
						// When non of the previous
						// parameters is given, this
						// behavior makes just a existence
						// check.
						if($this->_parser->$varname) {
							$isTrue = true;
						}
					}
				}
				//
				// If there's a parameter '!' set, whatever the
				// current evaluation result is, it is toggled
				// with it opposite.
				if(isset($params["!"])) {
					$isTrue = !$isTrue;
				}
			}
			//
			// If the evaluation is true, the contents of the
			// behavior's node must be returned.
			if($isTrue) {
				//
				// Since node children may be nested behaviors,
				// they'll be returned parsed.
				$out = $this->_node->parseChildren();
			} else {
				//
				// If the condition is false, an empty string is
				// returned.
				$out = "";
			}
		}
		//
		// Returning evaluation results.
		return $out;
	}
	/**
	 * This method redefines the inherited class initializer.
	 */
	protected function init() {
		//
		// Setting a type of warnings used when a IF condition is created
		// but there's no variable to evaluate.
		$this->_parser->setWarning(WCParserBehaviorIF::WarningNONAME, false, false, "IF: no variable name. Use keyword 'var'");
		//
		// Setting a type of warnings used when a variable has to be an
		// array and it's not.
		$this->_parser->setWarning(WCParserBehaviorIF::WarningNOTARRAY, false, false, "IF: variable is not an array");
	}
}
